﻿using System;
using UnityEngine;
using UBlockly.Scriptable;
using System.Collections.Generic;
using UBlockly.Compotent;

/// <summary>
/// 块类型 - 组成
/// </summary>
public enum BlockType
{
    PackType,
    SlotType,
}

namespace UBlockly.UI
{
    public interface IChangeNotify
    {
        void OnChangeNotify();
    }
    
    public abstract class Node : IDisposable,IChangeNotify
    {
        private long id;
        private NSlotPair[] slotPairs;
        public long Id => id;
        public BlockObject Block;
        public NodePacker NodePacker;
        public NodeScriptable Scriptable;
        public System.Action BodyChangeNotify;

        public Node(BlockObject block, NodeScriptable script)
        {
            if (script != null)
            {
                Scriptable = script;
                if (script.ParamType != ILFunResult.VoidR && script.ParamType != ILFunResult.None)
                {
                    NodePacker = new NodePacker(this,
                        block.Find("PackInfo").GetComponentInChildren<ParamGetterCompotent>());   
                }
            }
            if (block != null)
            {
                Block = block;  
                Block.BindNode(this);
            }
        }

        public virtual void Init()
        {
            this.id = UBtil.ApplyNodeIndex();
            NodePacker?.Init();

            Block.name = "block-" + id;
            var assist = Block.GetComponent<NodeConfigAssist>();
            if (Block.BlockType == BlockType.SlotType)
            {
                var temppairs = assist.CreateSlotPiars(id);
                slotPairs = new NSlotPair[temppairs.Length];
                temppairs.CopyTo(slotPairs, 0);
            }
            else
            {
                
            }

            //node.GetPhysic().BindPackRect(assist.CreatePacks(node.Id));
            //node.GetPhysic().BindSlotPair(assist.CreateSlotPiars(node.Id));
            GameObject.Destroy(assist);
        }

        public void ResizeNode()
        {
            Block.ReSize();
            if (Block.BlockType == BlockType.SlotType)
            {
                (Block.Node.List as ULinkedList<Node>)?.DoNotify();
            }
            else
            {
                OnChangeNotify();
            }
        }

        public NSlotPair GetPair(int index = 0)
        {
            index = Mathf.Clamp(index, 0, slotPairs.Length);
            return slotPairs[index];
        }

        public NSlotPair[] GetPairs()
        {
            return slotPairs;
        }

        public virtual void Dispose()
        {
            GameObject.Destroy(Block.gameObject);
        }

        /// <summary>
        /// 整个身体的节点，任何一个节点发生改变时，头都会响应到事件，然后重新计算
        /// 当前node为head时，才会被调用
        /// </summary>
        public void OnChangeNotify()
        {
            Debug.LogError($"我是{id},我的一部分发生改变");
            (Block.Node.List as ULinkedList<Node>)?.PhysicSort();
            BodyChangeNotify?.Invoke();
        }
    }

    public interface IBranchNode
    {
        bool IsNullBranch { get; }
        Node Node { get; }
        int BranchCount { get; }
        LinkedList<Node> GetBranch(int id);
        Node GetBranchRoot(int id);
        void CreateBranchRoot(int branchId,EmptyScriptNode rootNode);

        void AnyBranchChangeNotify();
    }

    public abstract class BranchNode : Node, IBranchNode
    {
        public abstract bool IsNullBranch { get; }
        public abstract int BranchCount { get; }
        public Node Node => this;
        public BranchNode(BlockObject block, NodeScriptable x) : base(block,x) { }

        public abstract LinkedList<Node> GetBranch(int id);

        public abstract Node GetBranchRoot(int id);

        public void CreateBranchRoot(int branchId, EmptyScriptNode rootNode)
        {
            GetBranch(branchId).AddFirst(rootNode);
            rootNode.BodyChangeNotify = AnyBranchChangeNotify;
        }

        public void AnyBranchChangeNotify()
        {
            Debug.LogError("有分支发生改变");
            Block.ReSize();
            (Block.Node.List as ULinkedList<Node>).DoNotify();
        }
    }

    /// <summary>
    /// script为空的node
    /// </summary>
    public sealed class EmptyScriptNode : Node
    {
        public EmptyScriptNode(BlockObject block) : base(block, null) { }

    }

    /// <summary>
    /// block为空的node
    /// </summary>
    public sealed class EmptyBlockNode : Node
    {
        public EmptyBlockNode(NodeScriptable scriptable) : base(null, scriptable) { }

    }
}

